#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
import numpy as np


# 固定尺寸
def resizeImg(image, height=900):
    h, w = image.shape[:2]
    pro = height / h
    size = (int(w * pro), int(height))
    img = cv2.resize(image, size)
    return img


# 边缘检测
def getCanny(image):
    # 高斯模糊
    binary = cv2.GaussianBlur(image, (3, 3), 2, 2)
    # 边缘检测
    binary = cv2.Canny(binary, 60, 240, apertureSize=3)
    # 膨胀操作，尽量使边缘闭合
    kernel = np.ones((3, 3), np.uint8)
    binary = cv2.dilate(binary, kernel, iterations=1)
    return binary


# 求出面积最大的轮廓
def findMaxContour(image):
    # 寻找边缘
    contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    # 计算面积
    max_area = 0.0
    max_contour = []
    for contour in contours:
        currentArea = cv2.contourArea(contour)
        if currentArea > max_area:
            max_area = currentArea
            max_contour = contour
    return max_contour, max_area


# 多边形拟合凸包的四个顶点
def getBoxPoint(contour):
    # 多边形拟合凸包
    hull = cv2.convexHull(contour)
    epsilon = 0.02 * cv2.arcLength(contour, True)
    approx = cv2.approxPolyDP(hull, epsilon, True)
    approx = approx.reshape((len(approx), 2))
    return approx


# 适配原四边形点集
def adaPoint(box, pro):
    box_pro = box
    if pro != 1.0:
        box_pro = box/pro
    box_pro = np.trunc(box_pro)
    return box_pro


# 四边形顶点排序，[top-left, top-right, bottom-right, bottom-left]
def orderPoints(pts):
    rect = np.zeros((4, 2), dtype="float32")
    s = pts.sum(axis=1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts, axis=1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect


# 计算长宽
def pointDistance(a, b):
    return int(np.sqrt(np.sum(np.square(a - b))))


# 透视变换
def warpImage(image, box):
    w, h = pointDistance(box[0], box[1]), \
           pointDistance(box[1], box[2])                       #
    dst_rect = np.array([[0, 0],
                         [w - 1, 0],
                         [w - 1, h - 1],
                         [0, h - 1]], dtype='float32') # dst_rect 是
    #根据四个点的坐标画点
    for i in range(4):
        cv2.circle(image, (int(box[i][0]), int(box[i][1])), 10, (0, 255, 0), -1)
        # 画出每个点之间的倾斜度
        cv2.line(image, (int(box[i][0]), int(box[i][1])), (int(box[(i + 1) % 4][0]), int(box[(i + 1) % 4][1])), (0, 0, 255), 2)
        # 每条线的中点画出每条线的名字i

        cv2.putText(image, str(i), (int((box[i][0] + box[(i + 1) % 4][0]) / 2), int((box[i][1] + box[(i + 1) % 4][1]) / 2)), cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 255, 0), 2)
        print("线段"+str(i)+"的坐标为："+str(box[i])+"和"+str(box[(i + 1) % 4]))
        x1 = box[i][0]
        x2 = box[(i + 1) % 4][0]
        y1 = box[i][1]
        y2 = box[(i + 1) % 4][1]
        if x2 - x1 == 0:
            print("直线是竖直的")
            result = 90
        elif y2 - y1 == 0:
            print("直线是水平的")
            result = 0
        else:
            # 计算斜率
            k = -(y2 - y1) / (x2 - x1)
            # 求反正切，再将得到的弧度转换为度
            result = np.arctan(k) * 57.29577
            print("直线倾斜角度为：" + str(result) + "度")



    #显示图片


















    cv2.imshow('box', image)
    #保存图片
    cv2.imwrite(r'.\result.jpg',image)

    M = cv2.getPerspectiveTransform(box, dst_rect)  #
    warped = cv2.warpPerspective(image, M, (w, h))
    return warped


if __name__ == '__main__':
    path = r'image/11.jpg'
    outpath = r'.\result2.jpg'
    image = cv2.imread(path)
    ratio = 900 / image.shape[0]  # 900是期望的高度
    img = resizeImg(image) #
    binary_img = getCanny(img)#边缘检测 识别土灰色









    #降噪





    max_contour, max_area = findMaxContour(binary_img)
    boxes = getBoxPoint(max_contour)
    boxes = adaPoint(boxes, ratio)
    boxes = orderPoints(boxes)

    # 显示轮廓
    cv2.drawContours(img, [max_contour], -1, (0, 0, 255), 2)
    cv2.imshow('contour', img)

    # 显示顶点





    # #     cv2.circle(img, (int(boxes[i][0]), int(boxes[i][1])), 10, (0, 255, 0), -1)
    # cv2.imshow('box', img)





    # 透视变化
    warped = warpImage(image, boxes)
    cv2.imshow('warpImage', warped)
    cv2.waitKey(0)
